// Fill out your copyright notice in the Description page of Project Settings.


#include "Test/SharedTest/Test1.h"

DEFINE_LOG_CATEGORY(TestLog);

Test1::Test1()
{
	UE_LOG(TestLog, Warning, TEXT("Test1 Construct"));
}

void Test1::TestPring()
{
	UE_LOG(TestLog, Warning, TEXT("Test1::TestPring"));
}

Test1::~Test1()
{
	UE_LOG(TestLog, Warning, TEXT("Test1 Destruct"));
}

void ClassTop::MyFunc()
{
	UE_LOG(TestLog, Warning, TEXT("ClassTop::MyFunc %d"), Only);
}

TestManager::TestManager()
{
	UE_LOG(TestLog, Warning, TEXT("TestManager Construct"));
}

TestManager::~TestManager()
{
	UE_LOG(TestLog, Warning, TEXT("TestManager Destruct"));
}

void TestManager::SharePtr::CreateSharePtr()
{
	TSharedPtr<ClassTop> shareptr = MakeShareable(new ClassTop());
	// 也可以通过.Get()判断是否为空
	if (shareptr.IsValid())
	{
		shareptr->MyFunc();
	}
}

void TestManager::SharePtr::SharePtrToSharePtr()
{
	{
		// 这样写是错误的，指向的实例必须为子对象，否则StaticCastSharedPtr会返回nullptr，无法从ClassBase强转为ClassTop
		TSharedPtr<ClassBase> ParentPtr = MakeShareable(new ClassBase());
		TSharedPtr<ClassTop> ChidrenPtr = StaticCastSharedPtr<ClassTop>(ParentPtr);
		// 此时ChidrenPtr为空
		if (ChidrenPtr.IsValid())
		{
			ChidrenPtr->MyFunc();
		}
	}

	{
		TSharedPtr<ClassBase> ParentPtr = MakeShareable(new ClassTop());
		TSharedPtr<ClassTop> ChidrenPtr = StaticCastSharedPtr<ClassTop>(ParentPtr);
		// 此时ChidrenPtr有值
		if (ChidrenPtr.IsValid())
		{
			ChidrenPtr->MyFunc();
		}
	}
}

void TestManager::SharePtr::ConstSharePtrToSharePtr()
{
	TSharedPtr<ClassBase> ParentPtr = MakeShareable(new ClassTop());
	{
		// 错误写法, 不能通过ConstCastSharedPtr直接转成派生类
		// TSharedPtr<ClassTop> ChidrenPtr = ConstCastSharedPtr<ClassTop>(ParentPtr);
	}

	{
		// 正确写法1
		// 先通过ConstCastSharedPtr转成非const的基类
		TSharedPtr<ClassBase> ParentPtr1 = ConstCastSharedPtr<ClassBase>(ParentPtr);

		// 再通过StaticCastSharedPtr转换
		TSharedPtr<ClassTop> ChidrenPtr = StaticCastSharedPtr<ClassTop>(ParentPtr1);
		if (ChidrenPtr.IsValid())
		{
			ChidrenPtr->MyFunc();
		}
	}

	{
		// 正确写法2
		// 直接通过StaticCastSharedPtr转换
		TSharedPtr<ClassTop> ChidrenPtr = StaticCastSharedPtr<ClassTop>(ParentPtr);
		if (ChidrenPtr.IsValid())
		{
			ChidrenPtr->MyFunc();
		}
	}
}

void TestManager::SharePtr::SharePtrToShareRef()
{
	TSharedPtr<ClassBase> ptr = MakeShareable<ClassBase>(new ClassTop());
	if (ptr.IsValid())
	{
		TSharedRef<ClassBase> ref = ptr.ToSharedRef();
	}
}

void TestManager::ShareRef::CreateShareRef()
{
	// TSharedRef没有IsValid方法, 因为它一直是有效的
	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
	ref->nBase;
}

void TestManager::ShareRef::ShareRefToShareRef()
{
	// TSharedRef没有IsValid方法, 因为它一直是有效的
	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
	TSharedRef<ClassTop> refCast = StaticCastSharedRef<ClassTop>(ref);
	refCast->MyFunc();
}

void TestManager::ShareRef::ConstShareRefToShareRef()
{
	// TSharedRef没有IsValid方法, 因为它一直是有效的
	const TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());

	{
		// 错误写法, 不能通过ConstCastSharedRef直接转成派生类.
		// TSharedRef<ClassTop> refcast1 = ConstCastSharedRef<ClassTop>(ref);
	}
	{
		// 正确写法1, 先通过ConstCastSharedRef转换城非Const的基类
		TSharedRef<ClassBase> refcast1 = ConstCastSharedRef<ClassBase>(ref);
		// 再通过StaticCastSharedRef转换
		TSharedRef<ClassTop> refcast2 = StaticCastSharedRef<ClassTop>(refcast1);
		refcast2->MyFunc();
	}

	{
		// 正确写法2
		// 直接通过StaticCastSharedRef转换
		TSharedPtr<ClassTop> refcast = StaticCastSharedRef<ClassTop>(ref);
		if (refcast.IsValid())
		{
			refcast->MyFunc();
		}
	}
}

void TestManager::ShareRef::ShareRefToSharePtr()
{
	TSharedRef<ClassBase> ref = MakeShareable(new ClassTop());
	// 直接=就行
	TSharedPtr<ClassBase> ptr = ref;
}

void TestManager::WeakPtr::CreateWeakPtr()
{
	TSharedPtr<ClassBase> SharePtr = MakeShareable(new ClassBase());
	// 通过SharePtr初始化TWeakPtr
	TWeakPtr<ClassBase> WeakPtr1 = SharePtr;
	TWeakPtr<ClassBase> WeakPtr2(SharePtr);

	// 通过ShareRef初始化TWeakPtr
	TSharedRef<ClassBase> ref = SharePtr.ToSharedRef();
	TWeakPtr<ClassBase> WeakPtr3 = ref;
	TWeakPtr<ClassBase> WeakPtr4(ref);
}

void TestManager::WeakPtr::WeakPtrToSharePtr()
{
	TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
	// 通过SharePtr初始化TWeakPtr
	TWeakPtr<ClassBase> WeakPtr = ptr;

	// 利用WeakPtr的.Pin()函数将WeakPtr转成SharedPtr
	TSharedPtr<ClassBase> WeakPtrToSharePtrObj = WeakPtr.Pin();
	if (WeakPtrToSharePtrObj.IsValid())
	{
		// tdo smth...
	}
}

void TestManager::WeakPtr::WeakPtrToShareRef()
{
	TSharedPtr<ClassBase> ptr = MakeShareable(new ClassTop());
	// 通过SharePtr初始化TWeakPtr
	TWeakPtr<ClassBase> WeakPtr = ptr;

	// 利用WeakPtr的.Pin()函数将WeakPtr转成SharedPtr
	TSharedPtr<ClassBase> WeakPtrToSharePtrObj = WeakPtr.Pin();
	if (WeakPtrToSharePtrObj.IsValid())
	{
		// 利用TSharedPtr的ToSharedRef()函数将TSharedPtr转换成TSharedRef
		TSharedRef<ClassBase> ref = WeakPtrToSharePtrObj.ToSharedRef();
	}
}

void TestManager::SharedFromThisTest()
{
	TSharedPtr<ClassChidren> ptr = MakeShareable(new ClassChidren());
	if (ptr.IsValid())
	{
		// 我们通过.Get()将TSharedPtr转换成C++ 原生指针
		ClassChidren* pOriginPtr = ptr.Get();

		// 现在我们想将pOriginPtr这个原生C++指针怎么转回智能指针呢？
		{
			// 错误的用法, 也能这么用, 但是不建议
			// TSharedPtr<ClassParent> ptr = MakeShareable(pOriginPtr);

			// 错误的用法, AsShared()不能用派生类接
			// TSharedPtr<ClassParent> ptr22 = pOriginPtr->AsShared();
		}
		{
			// 正确的用法, AsShared()不能用基类接(基类指的是你继承自TSharedFromThis的那个类)
			TSharedPtr<ClassParent> ptr2 = pOriginPtr->AsShared();
			TSharedPtr<ClassChidren> ptr3 = StaticCastSharedPtr<ClassChidren>(ptr2);
			if (ptr3.IsValid())
			{
				// tdo smth...
			}
		}
	}
}
